package core;

import plan.*;
import plan.ThreadGroup;

import javax.swing.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 压测工具类
 */
public class ConcurrentTestUtil {

    /**
     * 压力测试方法
     *
     */
    public static void doRequest(TestPlan testPlan,JProgressBar jProgressBar) throws Exception {
        ThreadGroup threadGroup = testPlan.getThreadGroup();
        HttpRequest httpRequest = testPlan.getHttpRequest();
        Result re = testPlan.getResult();
        TestReport testReport = testPlan.getTestReport();

        String url = httpRequest.getUrl();
        int requestNum = threadGroup.getSamples();
        int concurrentNum = threadGroup.getThreadNum();
        String param = httpRequest.getParam();
        //创建1个线程池
        ExecutorService executor = Executors.newFixedThreadPool(concurrentNum);
        //存放请求响应时间的列表
        List<Long> timeList = new ArrayList<>();
        //记录开始时间（方便计算总时长）
        long startTime = System.currentTimeMillis();
        //记录出错线程数
        List<Long> errorNum = new ArrayList<>();
        //计时器
        CountDownLatch latch = new CountDownLatch(requestNum);
        //发起网络请求
        AtomicReference<String> result = new AtomicReference<>();

        if("GET".equals(httpRequest.getFuc())){
            //循环发起请求
            for (int i = 0; i < requestNum; i++) {
                executor.execute(() -> {
                    long start = System.currentTimeMillis();
                    result.set(HttpUtil.sendGet(url, param,httpRequest.getEncoding()));
                    timeList.add(System.currentTimeMillis() - start);
                    latch.countDown();
                    if("error".equals(result.toString())) {
                        errorNum.add(System.currentTimeMillis());
                    }

                });
            }
        }else if("POST".equals(httpRequest.getFuc())){
            //循环发起请求
            for (int i = 0; i < requestNum; i++) {
                executor.execute(() -> {
                    long start = System.currentTimeMillis();
                    result.set(HttpUtil.sendPost(url, param,httpRequest.getEncoding()));
                    timeList.add(System.currentTimeMillis() - start);
                    latch.countDown();
                    if("error".equals(result.toString())) {
                        errorNum.add(System.currentTimeMillis());
                    }
                });
            }
        }

        latch.await();
        //计算请求总时间
        long totalCostTime = 0;
        for (int i = 0; i < timeList.size(); i++) {
            long time = timeList.get(i);
            totalCostTime += time;
        }
        jProgressBar.setValue(100);
        executor.shutdown();
        //对数据进行排列
        Collections.sort(timeList);


        requestNum = timeList.size();
        re.setRes(result.toString());
        //打印
        System.out.println("压测的网址: " + url);
        System.out.println("压测总次数: " + requestNum);
        System.out.println("并发线程数: " + concurrentNum);
        System.out.println("总花费时间（毫秒）: " + totalCostTime);
        testReport.setAverage(((double) totalCostTime / requestNum));
        System.out.println("平均花费时间（毫秒）: " + testReport.getAverage());
        testReport.setMedia(timeList.get(50 * requestNum / 100));
        testReport.setLine95(timeList.get(95 * requestNum / 100));
        System.out.println("95%时间（毫秒）: " + testReport.getLine95());
        testReport.setLine90(timeList.get(90 * requestNum / 100));
        testReport.setLine99(timeList.get(99 * requestNum / 100));
        testReport.setError(((errorNum.size() / requestNum) * 100));
        testReport.setMin(timeList.get(0));
        testReport.setMax(timeList.get(timeList.size() - 1));
        System.out.println("错误率：" + testReport.getError() + "%");
        testReport.setThroughput((requestNum / (totalCostTime / 1000.0)));
        System.out.println("吞吐量：" + testReport.getThroughput());
        System.out.println("---------------------------");
        for (int i = 0; i < timeList.size(); i++) {
            long time = timeList.get(i);
            System.out.println("第" + i + "次： " + time + "毫秒");
        }
        System.out.println("---------------------------");
    }
}